import { describe, it, expect, beforeEach } from 'vitest';
import { createPinia, setActivePinia } from 'pinia';
import { useStitchingStore } from '../../src/stores/stitchingStore';
import imageStitchingService from '../../src/services/ImageStitchingService';
import { generateTestImages, generateTestImagesWithSizes } from './utils/imageGenerator';
import { measurePerformance, logPerformanceResult, runPerformanceTest } from './utils/performanceUtils';
import type { UploadedImage, StitchingOptions } from '../../src/types/models';

// Helper function to convert File objects to UploadedImage objects
async function filesToUploadedImages(files: File[]): Promise<UploadedImage[]> {
  return files.map((file, index) => {
    // Extract dimensions from filename
    const match = file.name.match(/(\d+)x(\d+)/);
    const width = match ? parseInt(match[1]) : 800;
    const height = match ? parseInt(match[2]) : 600;
    
    return {
      id: `test-${index}`,
      file,
      url: URL.createObjectURL(file),
      name: file.name,
      width,
      height,
      fileSize: file.size,
      format: file.name.endsWith('.png') ? 'png' : 'jpg'
    };
  });
}

describe('Image Stitching Performance', () => {
  beforeEach(() => {
    // Create a fresh Pinia instance for each test
    setActivePinia(createPinia());
  });
  
  it('should measure stitching performance with different image counts', async () => {
    // Test with different numbers of images
    const imageCounts = [4, 9, 16];
    
    for (const count of imageCounts) {
      // Generate test images
      const files = await generateTestImages(count, 800, 800, 600, 600);
      const images = await filesToUploadedImages(files);
      
      // Calculate total pixels
      const totalPixels = images.reduce((sum, image) => sum + image.width * image.height, 0);
      
      // Define stitching options
      const options: StitchingOptions = {
        arrangement: 'grid',
        spacing: 0,
        maxWidth: 12000,
        maxHeight: 12000,
        backgroundColor: '#ffffff'
      };
      
      // Measure performance
      const { performance } = await measurePerformance(
        `Stitch ${count} images (grid arrangement)`,
        async () => {
          return await imageStitchingService.stitchImages(images, options);
        },
        {
          imageCount: count,
          totalPixels,
          arrangement: options.arrangement
        }
      );
      
      // Log performance result
      logPerformanceResult(performance);
      
      // Verify that the stitching was successful
      expect(performance.duration).toBeGreaterThan(0);
    }
  });
  
  it('should measure stitching performance with different arrangements', async () => {
    // Generate test images
    const files = await generateTestImages(9, 800, 800, 600, 600);
    const images = await filesToUploadedImages(files);
    
    // Calculate total pixels
    const totalPixels = images.reduce((sum, image) => sum + image.width * image.height, 0);
    
    // Test with different arrangements
    const arrangements: Array<'grid' | 'horizontal' | 'vertical'> = ['grid', 'horizontal', 'vertical'];
    
    for (const arrangement of arrangements) {
      // Define stitching options
      const options: StitchingOptions = {
        arrangement,
        spacing: 0,
        maxWidth: 12000,
        maxHeight: 12000,
        backgroundColor: '#ffffff'
      };
      
      // Measure performance
      const { performance } = await measurePerformance(
        `Stitch 9 images (${arrangement} arrangement)`,
        async () => {
          return await imageStitchingService.stitchImages(images, options);
        },
        {
          imageCount: images.length,
          totalPixels,
          arrangement
        }
      );
      
      // Log performance result
      logPerformanceResult(performance);
      
      // Verify that the stitching was successful
      expect(performance.duration).toBeGreaterThan(0);
    }
  });
  
  it('should measure stitching performance with different image sizes', async () => {
    // Test with different image sizes
    const imageSizes: Array<[number, number]> = [
      [800, 600],    // Small: 0.48 MP
      [1600, 1200],  // Medium: 1.92 MP
      [3200, 2400]   // Large: 7.68 MP
    ];
    
    for (const [width, height] of imageSizes) {
      // Generate test images
      const files = await generateTestImagesWithSizes(Array(4).fill([width, height]));
      const images = await filesToUploadedImages(files);
      
      // Calculate total pixels
      const totalPixels = images.reduce((sum, image) => sum + image.width * image.height, 0);
      
      // Define stitching options
      const options: StitchingOptions = {
        arrangement: 'grid',
        spacing: 0,
        maxWidth: 12000,
        maxHeight: 12000,
        backgroundColor: '#ffffff'
      };
      
      // Measure performance
      const { performance } = await measurePerformance(
        `Stitch 4 images of size ${width}x${height} (${(width * height / 1000000).toFixed(2)} MP each)`,
        async () => {
          return await imageStitchingService.stitchImages(images, options);
        },
        {
          imageCount: images.length,
          totalPixels,
          imageSize: `${width}x${height}`,
          megapixelsPerImage: (width * height / 1000000).toFixed(2)
        }
      );
      
      // Log performance result
      logPerformanceResult(performance);
      
      // Verify that the stitching was successful
      expect(performance.duration).toBeGreaterThan(0);
    }
  });
  
  it('should measure stitching store performance', async () => {
    // Get stitching store
    const stitchingStore = useStitchingStore();
    
    // Generate test images
    const files = await generateTestImages(9, 800, 800, 600, 600);
    const images = await filesToUploadedImages(files);
    
    // Calculate total pixels
    const totalPixels = images.reduce((sum, image) => sum + image.width * image.height, 0);
    
    // Define stitching options
    const options: StitchingOptions = {
      arrangement: 'grid',
      spacing: 0,
      maxWidth: 12000,
      maxHeight: 12000,
      backgroundColor: '#ffffff'
    };
    
    // Mock the uploadStore.images
    stitchingStore.$patch({
      uploadImages: images
    });
    
    // Measure performance
    const { performance } = await measurePerformance(
      'Stitching store stitchImages',
      async () => {
        return await stitchingStore.stitchImages(options);
      },
      {
        imageCount: images.length,
        totalPixels,
        arrangement: options.arrangement
      }
    );
    
    // Log performance result
    logPerformanceResult(performance);
    
    // Verify that the stitching was successful
    expect(performance.duration).toBeGreaterThan(0);
    expect(stitchingStore.stitchedImage).not.toBeNull();
  });
  
  it('should measure metadata generation performance', async () => {
    // Generate test images
    const files = await generateTestImages(16, 800, 800, 600, 600);
    const images = await filesToUploadedImages(files);
    
    // Define stitching options
    const options: StitchingOptions = {
      arrangement: 'grid',
      spacing: 0,
      maxWidth: 12000,
      maxHeight: 12000,
      backgroundColor: '#ffffff'
    };
    
    // Stitch images first
    const stitchedImage = await imageStitchingService.stitchImages(images, options);
    
    // Measure metadata generation performance
    const { performance } = await measurePerformance(
      'Generate metadata for 16 images',
      async () => {
        return imageStitchingService.generateMetadata(images, stitchedImage, options);
      },
      {
        imageCount: images.length,
        stitchedImageSize: `${stitchedImage.width}x${stitchedImage.height}`
      }
    );
    
    // Log performance result
    logPerformanceResult(performance);
    
    // Verify that the metadata generation was successful
    expect(performance.duration).toBeGreaterThan(0);
  });
});